#include <sys/stat.h>

inline int run_deal_(const std::unordered_set<int>& execute_issue_numbers = std::unordered_set<int>())
{
  // 1. Load campaign_status from cc_json.dat
  std::unordered_map<std::string, uint8_t> campaign_status;
  {
    struct stat file_stat;
    if (stat("cc_json.dat", &file_stat) == 0)
    {
      size_t file_size = file_stat.st_size;
      void* buffer = malloc(file_size);
      if (buffer)
      {
        dat_t dat(buffer, file_size);
        if (dat.get_("cc_json.dat", 0, file_size) == 0)
        {
          cc_deserialize_(campaign_status, buffer);
        }
        free(buffer);
      }
    }
  }
  // 2. Load jira_issues from cc_jira.dat
  std::vector<jira_s> jira_issues;
  {
    struct stat file_stat;
    if (stat("cc_jira.dat", &file_stat) == 0)
    {
      size_t file_size = file_stat.st_size;
      void* buffer = malloc(file_size);
      if (buffer)
      {
        dat_t dat(buffer, file_size);
        if (dat.get_("cc_jira.dat", 0, file_size) == 0)
        {
          cc_deserialize_(jira_issues, buffer);
        }
        free(buffer);
      }
    }
  }
  // 3. Extract campaigns for each JIRA entry
  std::unordered_map<std::string, std::vector<std::pair<std::string, uint8_t>>> jira_campaigns;
  for (const auto& jira_entry : jira_issues)
  {
    std::vector<std::pair<std::string, uint8_t>> campaigns = campaign_names_(jira_entry, campaign_status);
    if (!campaigns.empty())
    {
      jira_campaigns[jira_entry.key] = campaigns;
    }
  }
  // 3.5. Veto JIRA_ONLY campaigns that are prefixes of all JSON campaigns
  campaign_veto_abbreviations_(jira_campaigns);
  // 4. Determine should-be status for each JIRA entry
  std::unordered_map<std::string, std::pair<std::string, std::string>> jira_status_map; // <cur, should>
  for (const auto& jira_entry : jira_issues)
  {
    std::string cur_status = campaign_status_normalize_(jira_entry.status);
    std::vector<std::pair<std::string, uint8_t>> campaigns;
    auto it = jira_campaigns.find(jira_entry.key);
    if (it != jira_campaigns.end())
    {
      campaigns = it->second;
    }
    std::string should_be_status = campaign_status_should_be_(campaigns, jira_entry.created);
    jira_status_map[jira_entry.key] = std::make_pair(cur_status, should_be_status);
  }
  // 5. Collect and split mismatches
  std::vector<std::pair<const jira_s*, const std::vector<std::pair<std::string, uint8_t>>*>> mismatches_alpha; // with JIRA_ONLY
  std::vector<std::pair<const jira_s*, const std::vector<std::pair<std::string, uint8_t>>*>> mismatches_beta; // without JIRA_ONLY
  for (const auto& jira_entry : jira_issues)
  {
    auto status_it = jira_status_map.find(jira_entry.key);
    if (status_it == jira_status_map.end()) continue;
    const std::string& cur_status = status_it->second.first;
    const std::string& should_be_status = status_it->second.second;
    if (cur_status != should_be_status)
    {
      auto campaigns_it = jira_campaigns.find(jira_entry.key);
      bool has_jira_only = false;
      if (campaigns_it != jira_campaigns.end())
      {
        for (const auto& camp_pair : campaigns_it->second)
        {
          if (camp_pair.second == 2)
          {
            has_jira_only = true;
            break;
          }
        }
        if (has_jira_only) mismatches_alpha.push_back(std::make_pair(&jira_entry, &campaigns_it->second));
        else mismatches_beta.push_back(std::make_pair(&jira_entry, &campaigns_it->second));
      }
      else mismatches_beta.push_back(std::make_pair(&jira_entry, nullptr));
    }
  }
  // 6. Write mismatch_alpha.txt (with JIRA_ONLY)
  {
    std::ofstream out_file("mismatch_alpha.txt");
    if (out_file.is_open())
    {
      out_file << "JIRA Status Mismatches (with JIRA_ONLY campaigns)\n";
      out_file << std::string(70, '=') << "\n\n";
      out_file << "Total: " << mismatches_alpha.size() << "\n\n";
      for (size_t i = 0; i < mismatches_alpha.size(); ++i)
      {
        if (i > 0) out_file << std::string(70, '-') << "\n";
        const jira_s* jira_entry = mismatches_alpha[i].first;
        const std::vector<std::pair<std::string, uint8_t>>* campaigns = mismatches_alpha[i].second;
        auto status_it = jira_status_map.find(jira_entry->key);
        const std::string& cur_status = status_it->second.first;
        const std::string& should_be_status = status_it->second.second;
        out_file << "Mismatch #" << (i + 1) << " " << jira_entry->key << "\n";
        out_file << "  Summary:   " << jira_entry->summary << "\n";
        out_file << "  Status:    " << cur_status << " -> " << should_be_status << "\n";
        out_file << "  Action:    " << jira_transition_sequence_(cur_status, should_be_status) << "\n";
        if (campaigns)
        {
          std::vector<std::string> jira_only_campaigns;
          std::vector<std::pair<std::string, uint8_t>> json_campaigns;
          for (const auto& camp_pair : *campaigns)
          {
            if (camp_pair.second == 2) jira_only_campaigns.push_back(camp_pair.first);
            else json_campaigns.push_back(camp_pair);
          }
          if (!jira_only_campaigns.empty())
          {
            out_file << "  JIRA_ONLY: " << jira_only_campaigns[0];
            for (size_t j = 1; j < jira_only_campaigns.size(); ++j)
            {
              out_file << ", " << jira_only_campaigns[j];
            }
            out_file << "\n";
          }
          if (!json_campaigns.empty())
          {
            out_file << "  JSON:\n";
            const int content_column = 13;
            const int bracket_column = 56;
            for (const auto& camp_pair : json_campaigns)
            {
              std::string label = (camp_pair.second == 1) ? "ENABLED" : "DISABLED";
              std::string bracket_str = " [" + label + "]";
              int current_pos = content_column + static_cast<int>(camp_pair.first.length());
              int padding = (current_pos < bracket_column) ? (bracket_column - current_pos) : 1;
              out_file << std::string(content_column, ' ') << camp_pair.first << std::string(padding, ' ') << bracket_str << "\n";
            }
          }
        }
        std::string reason;
        if (should_be_status == "Closed")
        {
          int days = campaign_days_past_(jira_entry->created);
          reason = "Has JIRA only + " + std::to_string(days) + "d (>=60)";
        }
        else if (should_be_status == "To Do")
        {
          int days = campaign_days_past_(jira_entry->created);
          reason = "Has JIRA only + " + std::to_string(days) + "d (<60)";
        }
        else
        {
          reason = "Guided by campaigns in JSON";
        }
        out_file << "  Reason:    " << reason << "\n\n";
      }
      out_file.close();
    }
  }
  // 7. Write mismatch_beta.txt (without JIRA_ONLY)
  {
    std::ofstream out_file("mismatch_beta.txt");
    if (out_file.is_open())
    {
      out_file << "JIRA Status Mismatches (without JIRA_ONLY campaigns)\n";
      out_file << std::string(70, '=') << "\n\n";
      out_file << "Total: " << mismatches_beta.size() << "\n\n";
      for (size_t i = 0; i < mismatches_beta.size(); ++i)
      {
        if (i > 0) out_file << std::string(70, '-') << "\n";
        const jira_s* jira_entry = mismatches_beta[i].first;
        const std::vector<std::pair<std::string, uint8_t>>* campaigns = mismatches_beta[i].second;
        auto status_it = jira_status_map.find(jira_entry->key);
        const std::string& cur_status = status_it->second.first;
        const std::string& should_be_status = status_it->second.second;
        out_file << "Mismatch #" << (i + 1) << " " << jira_entry->key << "\n";
        out_file << "  Summary:   " << jira_entry->summary << "\n";
        out_file << "  Status:    " << cur_status << " -> " << should_be_status << "\n";
        out_file << "  Action:    " << jira_transition_sequence_(cur_status, should_be_status) << "\n";
        if (campaigns)
        {
          out_file << "  JSON:\n";
          const int content_column = 13;
          const int bracket_column = 56;
          for (const auto& camp_pair : *campaigns)
          {
            std::string label = (camp_pair.second == 1) ? "ENABLED" : "DISABLED";
            std::string bracket_str = " [" + label + "]";
            int current_pos = content_column + static_cast<int>(camp_pair.first.length());
            int padding = (current_pos < bracket_column) ? (bracket_column - current_pos) : 1;
            out_file << std::string(content_column, ' ') << camp_pair.first << std::string(padding, ' ') << bracket_str << "\n";
          }
        }
        std::string reason;
        if (should_be_status == "Enabled")
        {
          reason = "All enabled";
        }
        else if (should_be_status == "Open")
        {
          reason = "Has disabled";
        }
        else if (should_be_status == "Closed")
        {
          reason = "No campaigns";
        }
        else
        {
          reason = "Status logic error";
        }
        out_file << "  Reason:    " << reason << "\n\n";
      }
      out_file.close();
    }
  }
  // 8. Serialize mismatch_alpha to mismatch_alpha.dat
  {
    std::map<std::string, std::pair<std::string, std::string>> mismatch_alpha_map;
    for (const auto& mismatch : mismatches_alpha)
    {
      const jira_s* jira_entry = mismatch.first;
      auto status_it = jira_status_map.find(jira_entry->key);
      if (status_it != jira_status_map.end())
      {
        mismatch_alpha_map[jira_entry->key] = status_it->second;
      }
    }
    size_t serialized_size = cc_size_(mismatch_alpha_map);
    void* buffer = malloc(serialized_size);
    if (buffer)
    {
      size_t actual_size = cc_serialize_(mismatch_alpha_map, buffer);
      dat_t dat(buffer, actual_size);
      if (dat.new_("mismatch_alpha.dat", actual_size) == 0)
      {
        std::cout << "run_deal_(): Serialized mismatch_alpha to mismatch_alpha.dat (" << actual_size << " bytes)" << std::endl;
      }
      free(buffer);
    }
  }
  // 9. Serialize mismatch_beta to mismatch_beta.dat
  {
    std::map<std::string, std::pair<std::string, std::string>> mismatch_beta_map;
    for (const auto& mismatch : mismatches_beta)
    {
      const jira_s* jira_entry = mismatch.first;
      auto status_it = jira_status_map.find(jira_entry->key);
      if (status_it != jira_status_map.end())
      {
        mismatch_beta_map[jira_entry->key] = status_it->second;
      }
    }
    size_t serialized_size = cc_size_(mismatch_beta_map);
    void* buffer = malloc(serialized_size);
    if (buffer)
    {
      size_t actual_size = cc_serialize_(mismatch_beta_map, buffer);
      dat_t dat(buffer, actual_size);
      if (dat.new_("mismatch_beta.dat", actual_size) == 0)
      {
        std::cout << "run_deal_(): Serialized mismatch_beta to mismatch_beta.dat (" << actual_size << " bytes)" << std::endl;
      }
      free(buffer);
    }
  }
  std::cout << "\nTotal Mismatches: " << (mismatches_alpha.size() + mismatches_beta.size())
            << " out of " << jira_issues.size() << " issues\n";
  // 10. Execute transitions for specified issue numbers if provided
  if (!execute_issue_numbers.empty())
  {
    std::vector<std::string> issue_keys_to_execute;
    for (const auto& jira_entry : jira_issues)
    {
      int issue_num = jira_parse_number_(jira_entry.key);
      if (issue_num > 0 && execute_issue_numbers.find(issue_num) != execute_issue_numbers.end())
      {
        auto status_it = jira_status_map.find(jira_entry.key);
        if (status_it != jira_status_map.end())
        {
          const std::string& cur_status = status_it->second.first;
          const std::string& should_be_status = status_it->second.second;
          if (cur_status != should_be_status)
          {
            issue_keys_to_execute.push_back(jira_entry.key);
          }
        }
      }
    }
    if (!issue_keys_to_execute.empty())
    {
      std::cout << "\nExecuting transitions for " << issue_keys_to_execute.size() << " issues..." << std::endl;
      jira_c config;
      jira_execute_transitions_(issue_keys_to_execute, jira_status_map, config);
    }
    else
    {
      std::cout << "\nNo matching issues with mismatches found for execution" << std::endl;
    }
  }
  return 0;
}